#include "stdafx.h"
#include "BaseError.h"
#include "ErrorIds.h"

namespace ErrorHandling {

char* toString_FndErrorId(enum FndErrorId errId);
	
BaseError::BaseError(
		ErrorId err_id,
		ErrorSeverity sev,
		std::string description,
		IErrorSP cause) :
	id_(err_id),
	severity_(sev),
	description_(description),
	cause_(cause),
	timestamp_( time( NULL ) )
{
}

BaseError::~BaseError()
{
}

/// Copy ctor exists only to make sure we clone rather than copy cause_
BaseError::BaseError(const BaseError& b)
{
	id_ = b.id_;
	severity_ = b.severity_;
	description_ = b.description_;
	if (0 == b.cause_)
		cause_ = b.cause_;
	else
		setCause(b.cause_->clone());
	timestamp_ = b.timestamp_;
	sourceObjectName_ = b.sourceObjectName_;
	what_ = b.what_;
}

void BaseError::raise()
{
	throw *this;
}

IErrorSP BaseError::clone() const throw()
{
	IErrorSP retVal(new BaseError(*this));
	if (0 != cause_)
	{
		retVal->setCause(cause_->clone());
	}
	return retVal;
}

const char* BaseError::getName() const throw()
{
	return "BaseError";
}

std::string BaseError::toString() const throw()
{
	char timestr[64];
	struct tm timeinfo;
	errno_t err = localtime_s ( &timeinfo, &timestamp_ );
	if (0 != err)
	{
		strcpy_s(timestr, "Error getting time-stamp");
	}
	else
	{
		strftime( timestr, 64, "%c", &timeinfo );
	}

	std::ostringstream os;
	os 	<< timestr << " ("
		<< toString_FndErrorId((enum FndErrorId) id_) << "[" << id_ << "]:"
		<< severityName( severity_ ) << ":"
		<< sourceObjectName_ << ")"
		<< getDescription();

	IErrorSP cause = this->getCause();
	if (0 != cause)
	{
		os << "\n\t" << cause->what();
	}

	return os.str();
}

const char* BaseError::what() const throw()
{
	what_ = this->toString();
	return what_.c_str();
}

const ErrorId BaseError::getId() const throw()
{
	return id_;
}

const ErrorSeverity BaseError::getSeverity() const throw()
{
	return severity_;
}

const ErrorTimeStamp BaseError::getTimeStamp() const throw()
{
	return timestamp_;
}

const IErrorSP BaseError::getCause() const throw()
{
	return cause_;
}

std::string BaseError::getDescription() const throw()
{
	return description_;
}

void BaseError::setSourceObjectName(std::string sourceObjectName) throw()
{
	sourceObjectName_ = sourceObjectName;
}

std::string BaseError::getSourceObjectName() const throw()
{
	return sourceObjectName_;
}

bool BaseError::isSafe() const throw()
{
	return ((0 == cause_) || cause_.unique());
}

void BaseError::setSeverity( ErrorSeverity sev ) throw()
{
	severity_ = sev;
}

void BaseError::setCause( IErrorSP cause ) throw()
{
	cause_ = cause;
}


#define ENUM_TO_STRING_CASE(ENUM) case ENUM: return #ENUM;  break  // no trailing semicolon necessary

char* toString_FndErrorId(enum FndErrorId errId)
{
	switch(errId)
	{
		ENUM_TO_STRING_CASE(EID_FND_TIMEOUT);
		ENUM_TO_STRING_CASE(EID_FND_VERSION);
		ENUM_TO_STRING_CASE(EID_FND_RANGE);
		ENUM_TO_STRING_CASE(EID_FND_UNHANDLED_EXCEPTION);
		ENUM_TO_STRING_CASE(EID_FND_SEND_MESSAGE);
		ENUM_TO_STRING_CASE(EID_FND_WRONG_PAYLOAD);
		ENUM_TO_STRING_CASE(EID_FND_NOT_INITIALIZED);
		ENUM_TO_STRING_CASE(EID_FND_PROGRAMMING);
		ENUM_TO_STRING_CASE(EID_JOB_NO_THREADS);
		ENUM_TO_STRING_CASE(EID_NO_JOB);
		ENUM_TO_STRING_CASE(EID_JOB_OWNERSHIP);
		ENUM_TO_STRING_CASE(EID_JOB_NO_IDS);
		ENUM_TO_STRING_CASE(EID_JOB_INVALID_ID);
		ENUM_TO_STRING_CASE(EID_JOB_START_FAILED);
		ENUM_TO_STRING_CASE(EID_JOB_ABORTED);
		ENUM_TO_STRING_CASE(EID_JOB_DIED);
		ENUM_TO_STRING_CASE(EID_JOB_FAILED);
		ENUM_TO_STRING_CASE(EID_DIRECTOR_NO_SCHEDULE);
		ENUM_TO_STRING_CASE(EID_DIRECTOR_INITIALIZATION);
		ENUM_TO_STRING_CASE(EID_JOBSERVER_CREATION);
		ENUM_TO_STRING_CASE(EID_IMAGESERVER_CREATION);
		ENUM_TO_STRING_CASE(EID_COLLECTOR_CREATION);
		ENUM_TO_STRING_CASE(EID_MAPPER_CREATION);
		ENUM_TO_STRING_CASE(EID_ANALYZER_CREATION);
		ENUM_TO_STRING_CASE(EID_IMAGE_SET_ID_INVALID);
		ENUM_TO_STRING_CASE(EID_CANNOT_ALLOCATE);
		ENUM_TO_STRING_CASE(EID_SETS_NOT_ALL_RELEASED);
		ENUM_TO_STRING_CASE(EID_DUPLICATE_SETS_LOADED);
		ENUM_TO_STRING_CASE(EID_REPOSITORY_ERROR);
		ENUM_TO_STRING_CASE(EID_SW_ERROR_RECOVERY_TIMEOUT);
		ENUM_TO_STRING_CASE(EID_INVALID_IMAGE_SET_TYPE);
		ENUM_TO_STRING_CASE(EID_SCHEDULE_READ_FAILURE);
		ENUM_TO_STRING_CASE(EID_TEMPLATE_READ_FAILURE);
		ENUM_TO_STRING_CASE(EID_ANALYZER_TIMEOUT);
		ENUM_TO_STRING_CASE(EID_ANALYSIS_JOB_FAILED);
		ENUM_TO_STRING_CASE(EID_UNEXPECTED_CAN_MSG);
		ENUM_TO_STRING_CASE(EID_UNEXPECTED_RESPONSE_MSG);
		ENUM_TO_STRING_CASE(EID_EMERGENCY_MSG);
		ENUM_TO_STRING_CASE(EID_NETWORK_EVENT);
		ENUM_TO_STRING_CASE(EID_SEND_MESSAGE_ERROR);
		ENUM_TO_STRING_CASE(EID_ROBOT_INIT_FAILED);
		ENUM_TO_STRING_CASE(EID_ROBOT_GENERAL_ERROR);
		ENUM_TO_STRING_CASE(EID_ROBOT_TIMEOUT_ERROR);
		ENUM_TO_STRING_CASE(EID_HOME_FIRST_STAGE_FAILED);
		ENUM_TO_STRING_CASE(EID_HOME_SECOND_STAGE_FAILED);
		ENUM_TO_STRING_CASE(EID_LOAD_PVT_FAILED);
		ENUM_TO_STRING_CASE(EID_LOAD_PVT_CAN_STATUS_NOT_OK);
		ENUM_TO_STRING_CASE(EID_PERFORM_PVT_MOVE_FAILED);
		ENUM_TO_STRING_CASE(EID_PTP_MOVE_FAILED);
		ENUM_TO_STRING_CASE(EID_UNEXPECTED_COMMAND);
		ENUM_TO_STRING_CASE(EID_TIMESTAMP_TX_FAILED);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PLATFORM_INIT_FAILED);
		ENUM_TO_STRING_CASE(EID_PLATFORM_SET_INDICATOR_FAILED);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PLATFORM_UNEXPECTED_COMMAND);
		ENUM_TO_STRING_CASE(EID_COMMAND_EXECUTION_FAILED);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_BYPASS_SENSOR_BLOCKED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_WIDTH_NOT_AT_SPECIFIED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_NOT_HOMED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_A_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_SI_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_SA_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_SS_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_SR_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_WIDTH_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_WIDTH_PROX_BLOCK_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_LOW_AIR_PSI_MESSAGE);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_RELEASE_STATE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_RELEASE_PANEL_FREE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PRERELEASE_PANEL_FREE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_CHANGE_WIDTH_STATE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_CHANGE_WIDTH_HOMED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PRERELEASE_STATE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PANEL_SECURE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_SLOW_SENSOR_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_SECURE_PANEL_END_WITH_ERRORS);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_ALIGN_BEFORE_SLOW_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_RELOAD_PANEL_FREE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_RELOAD_PANEL_STATE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PANEL_FREE_WITH_ERRORS);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_LOAD_PANEL_SENSOR_BLOCKED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_FREE_PANEL_STOP_UP_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_FREE_PANEL_OPTO_BLOCK_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_LOAD_PANEL_NOT_RELEASED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_BOARD_STOPPED_TIMEOUT_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_UNSTOP_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_ACQ_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_ALIGN_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_RELEASE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_SEARCH_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_SLOW_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_SMEMA_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_EXIT_TIMEOUT);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_EXIT_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_LIFTED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_UNCLAMP_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_CLAMP_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_UNLIFT_ERROR);
		//broad-term error
		ENUM_TO_STRING_CASE(EID_CONVEYOR_HARDWARE_FAULT_ERROR);
		//broad-term error
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PANEL_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_PASS_THRU_SENSOR_BLOCKED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_IN_BYPASS_MODE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_HOME_PROX_BLOCK_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_HOMING_ERROR);

		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_A_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_SI_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_SI_DOWNSTREAM_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_SA_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_SS_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_INVALID_BUFFER_SR_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_BUFFER_ACQ_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_TO_BUFFER_RELEASE_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_BUFFER_SENSOR_BLOCKED_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_BUFFER_TO_EXIT_ERROR);
		ENUM_TO_STRING_CASE(EID_CONVEYOR_CANNOT_RESET_BELT_SLAVE_ERROR);
		ENUM_TO_STRING_CASE(EID_COLLISION_DETECTED);
		ENUM_TO_STRING_CASE(EID_PANEL_LENGTH_EXCEEDED_BUFFER_SPEC_ERROR);

		ENUM_TO_STRING_CASE(EID_RECONSTRUCTOR_LOST_IMAGE);
		ENUM_TO_STRING_CASE(EID_HEIGHT_DISTORTION_CORRECTION);
		ENUM_TO_STRING_CASE(EID_TIMEOUT_WAITING_FOR_IMAGE);
		ENUM_TO_STRING_CASE(EID_TGEN_MOTION_LIMITS_EXCEEDED);
		ENUM_TO_STRING_CASE(EID_SENSOR_INITIALIZE_CAMERA);
		ENUM_TO_STRING_CASE(EID_SENSOR_INITIALIZE_MIDDLEMAN);
		ENUM_TO_STRING_CASE(EID_SENSOR_INVALID_AOI_SETUP_HANDLE);
		ENUM_TO_STRING_CASE(EID_SENSOR_SET_TRIGGERS);
		ENUM_TO_STRING_CASE(EID_SENSOR_PUSH_TRIGGERS);
		ENUM_TO_STRING_CASE(EID_SENSOR_GET_SCAN_STATUS);
		ENUM_TO_STRING_CASE(EID_SENSOR_GET_GAIN_OFFSET);
		ENUM_TO_STRING_CASE(EID_SENSOR_RESET_ENCODER_COUNTS);
		ENUM_TO_STRING_CASE(EID_SENSOR_BEGIN_ENCODER_SYNC);
		ENUM_TO_STRING_CASE(EID_SENSOR_END_ENCODER_SYNC);
		ENUM_TO_STRING_CASE(EID_SENSOR_TRIGGER_LED_IMAGE);
		ENUM_TO_STRING_CASE(EID_SENSOR_CALIBRATION_READ_FAILED);
		ENUM_TO_STRING_CASE(EID_SENSOR_CALIBRATION_CRC_FAILED);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_OPEN);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_CLOSE);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_LOGGING_ENABLE);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_LOGGING_DISABLE);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_CLEAR_TRIGGER_SEND_BUFFER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_SEND_RAW_STRING);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_READ_CAMERA_REGISTER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_WRITE_CAMERA_REGISTER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_READ_REGISTER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_WRITE_REGISTER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_PUSH_TRIGGER);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_PUSH_END_OF_SCAN);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_SEND_COMMAND);
		ENUM_TO_STRING_CASE(EID_MIDDLEMAN_READ_EEPROM);
		ENUM_TO_STRING_CASE(EID_FRAME_GRABBER_TASK);
		ENUM_TO_STRING_CASE(EID_BAD_IMAGE_HEADER);
		ENUM_TO_STRING_CASE(EID_BAD_HEADER_CHECKSUM);
		ENUM_TO_STRING_CASE(EID_BAD_ROW_CHECKSUM);
		ENUM_TO_STRING_CASE(EID_Y_ENCODER_INTERPOLATION);
		ENUM_TO_STRING_CASE(EID_IMAGE_TRIGGER_COUNTS);
		ENUM_TO_STRING_CASE(EID_XYZ_ENCODER_POSITION);
		ENUM_TO_STRING_CASE(EID_STROBE_MONITOR);
		ENUM_TO_STRING_CASE(EID_TRIGGER_MODE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_BOARD_OPEN);
		ENUM_TO_STRING_CASE(EID_BITFLOW_BOARD_CLOSE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_CAMERA_FILE_OPEN);
		ENUM_TO_STRING_CASE(EID_BITFLOW_CAMERA_FILE_CLOSE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_CAMERA_FILE_ACTIVATE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_CAMERA_FILE_READ);
		ENUM_TO_STRING_CASE(EID_BITFLOW_IMAGE_DIMENSIONS);
		ENUM_TO_STRING_CASE(EID_BITFLOW_DMA_SETUP);
		ENUM_TO_STRING_CASE(EID_BITFLOW_DMA_CLEANUP);
		ENUM_TO_STRING_CASE(EID_BITFLOW_DMA_BUFFER_ALLOC);
		ENUM_TO_STRING_CASE(EID_BITFLOW_DMA_BUFFER_RELEASE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_DMA_BUFFER_SIZE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_ACQUISITION_DEFINE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_ACQUISITION_ACTIVATE);
		ENUM_TO_STRING_CASE(EID_BITFLOW_ACQUISITION_QUERY);
		ENUM_TO_STRING_CASE(EID_BITFLOW_ACQUISITION_START);
		ENUM_TO_STRING_CASE(EID_BITFLOW_ACQUISITION_STOP);
		ENUM_TO_STRING_CASE(EID_SYSTEM_COMPONENT_NOT_RESPONDING);

		default:
		    return "Unknown FndErrorId";
	}
}



} // end namespace ErrorHandling

BOOST_CLASS_EXPORT(ErrorHandling::BaseError);